#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright @ 2014 OPS, Qunar Inc. (qunar.com)
#
# Author: tingfang.bao <tingfang.bao@qunar.com>
# DateTime: 15-3-9 上午10:32
"""
Flask在代码执行时，包括两种不同的状态
1. application setup 状态: 模块级别，开始与Flask对象初始化，结束于第一个http请求的到达，有以下假设
    开发者可以安全的修改app对象
    还没有http请求到达
    必须自己获取app的引用，不能使用current_app这个魔法代理对象
2. request 状态，有以下规则
    可以使用上下文本地对象（包括flask.request, flask.session, flask.g等）
    所有代码都可以获取上下文本地对象
此外还有模糊的第３种状态：自己构造application context比如下面的with app.app_context()

app context最重要的作用：实现了current_app这个神奇的对象
flask的设计支柱之一，就是在同一个进程中可以运行多个app,这样http request就包含太多个功能。出现的问题就是，如何找到正确的app，
之前的做法是，自己去传递app，现在是current_app这个神奇的代理

创建application context
方式１：当request context pushed时，自动创建application context (如果有必要)
方式２：明确自己创建application context,如下所示

application context的位置
１．application context会按需创建／销毁，但是它是不会在线程之间移动的，也不会在多个request中共享．
２．非常适合存放数据库连接信息或对象
３．内部的栈对象：flask._app_ctx_stack
    Extensions are free to store additional information on the topmost level,
    assuming they pick a sufficiently unique name and should put their
    information there, instead of on the flask.g object which is reserved for user code


application context用法
典型用法：缓存每个http请求需要的资源，例如数据库连接
        多个app或扩展之间，需要的全局设置

最常见用法：
    隐式缓存资源对象
    application context　teardown时，销毁资源分配

例子：
    import sqlite3
    from flask import g

    def get_db() :
        db = getattr(g, ’ _database’ , None)
        if db is None:
            db = g. _database = connect_to_database()
        return db

    @app.teardown_appcontext
    def teardown_db(exception) :
        db = getattr(g, ’ _database’ , None)
        if db is not None:
            db. close()

    这里其实是隐式生成了LocalProxy
    from werkzeug.local import LocalProxy
    db = LocalProxy(get_db)

    以后就可以直接方法db了，内部直接调用get_db方法
"""

from flask import Flask, current_app, url_for

app = Flask(__name__)
app.config['SERVER_NAME'] = 'skyfree.com'
app.name = 'Test App'

"""
这里是明确的创建了一个app_context
"""


@app.route('/')
def index():
    return 'hello'


with app.app_context():
    print current_app.name

    # 如果定义了SERVER_NAME参数，这里即使没有flask.request也可以使用url_for
    # 如果注释掉app.config['SERVER_NAME'] = 'skyfree.com',就会出问题了。
    print url_for('index')